/*
 * @Author: Wangjun
 * @Date: 2021-05-31 10:59:09
 * @LastEditTime: 2025-05-23 15:38:33
 * @LastEditors: wangjun haodreams@163.com
 * @Description:字符串的操作
 * @FilePath: \libs\easy\string.go
 * hnxr
 */
package easy

import (
	"encoding/json"
	"regexp"
	"strconv"
	"strings"

	"gitee.com/haodreams/libs/fastmap"
)

// 解析布尔值
func ParseBool(val string) bool {
	switch val {
	case "true", "1", "TRUE", "True", "Y", "y":
		return true
	}
	return false
}

// 判断是否是字母
func IsLetter(b byte) bool {
	if ('a' <= b && b <= 'z') || ('A' <= b && b <= 'Z') {
		return true
	}
	return false
}

// 获取配置信息(k=v)
func GetParam(line, sep string) (kv map[string]string) {
	ss := strings.Split(line, sep)
	kv = map[string]string{}
	for _, s1 := range ss {
		s := strings.SplitN(s1, "=", 2)
		if len(s) < 2 {
			continue
		}
		s[0] = strings.TrimSpace(s[0])
		s[1] = strings.TrimSpace(s[1])
		kv[s[0]] = s[1]
	}
	return
}

func BoolValue(val string) bool {
	val = strings.ToUpper(val)
	val = strings.TrimSpace(val)
	switch val {
	case "TRUE", "Y", "ON", "YES", "1":
		return true
	}
	return false
}

func TrimSpaceList(s []string) {
	for i := range s {
		s[i] = strings.TrimSpace(s[i])
	}
}

// ToFirstUpper returns s with 首字母大写其他字母小写
func ToFirstUpper(s string) string {
	if len(s) == 0 {
		return s
	}

	var b strings.Builder
	b.Grow(len(s))
	c := s[0]
	if 'a' <= c && c <= 'z' {
		b.WriteByte(c - ('a' - 'A'))
	} else {
		b.WriteByte(c)
	}
	pos := 1
	for i := 1; i < len(s); i++ {
		c := s[i]
		if 'A' <= c && c <= 'Z' {
			c += 'a' - 'A'
			if pos < i {
				b.WriteString(s[pos:i])
			}
			b.WriteByte(c)
			pos = i + 1
		}
	}
	if pos < len(s) {
		b.WriteString(s[pos:])
	}
	return b.String()
}

// IndexArray 获取索引
func IndexArray(stringArray []string, str string) int {
	for i := range stringArray {
		if stringArray[i] == str {
			return i
		}
	}
	return -1
}

// String 去掉为0之后的字符
func String(data []byte) string {
	l := len(data)
	for i := 0; i < l; i++ {
		if data[i] == 0 {
			return string(data[:i])
		}
	}
	return string(data)
}

// ArrayIntToString int 转为 string
func ArrayIntToString[V fastmap.Key](vals []V) []string {
	ss := make([]string, len(vals))
	for i := range vals {
		ss[i] = strconv.FormatInt(int64(vals[i]), 10)
	}
	return ss
}

/**
 * @description: string 数组 转为int 数组
 * @param {[]string} svals
 * @return {*}
 */
func ArrayStringToInt(svals []string) (ivals []int) {
	ivals = make([]int, len(svals))
	idx := 0
	var err error
	for i := range svals {
		ivals[idx], err = strconv.Atoi(svals[i])
		if err != nil {
			continue
		}
		idx++
	}
	ivals = ivals[:idx]
	return
}

// HashSet 数据去重
func HashSet[G comparable](list []G) (hashSet []G) {
	hashSet = make([]G, len(list))
	mp := map[G]int{}
	idx := 0
	for i, g := range list {
		if _, ok := mp[g]; ok {
			continue
		}
		mp[g] = i
		hashSet[idx] = g
		idx++
	}

	return hashSet[:idx]
}

func ToJsonString(object interface{}, easyRead bool) string {
	if easyRead {
		data, err := json.MarshalIndent(object, "", "  ")
		if err != nil {
			return ""
		}
		return string(data)
	}
	data, err := json.Marshal(object)
	if err != nil {
		return ""
	}
	return string(data)
}

// 获取map的key

// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)
// and returns an array of slices of s. If all code points in s satisfy f(c) or the
// string is empty, an empty slice is returned.
//
// FieldsFunc makes no guarantees about the order in which it calls f(c)
// and assumes that f always returns the same value for a given c.
func FieldsFuncN(s string, f func(rune) bool, n int) []string {
	// A span is used to record a slice of s of the form s[start:end].
	// The start index is inclusive and the end index is exclusive.
	type span struct {
		start int
		end   int
	}
	spans := make([]span, 0, 32)

	// Find the field start and end indices.
	// Doing this in a separate pass (rather than slicing the string s
	// and collecting the result substrings right away) is significantly
	// more efficient, possibly due to cache effects.
	start := -1 // valid span start if >= 0
	count := 0
	for end, rune := range s {
		if f(rune) {
			count++
			if count >= n {
				if start < 0 {
					start = end
				}
				break
			}
			if start >= 0 {
				spans = append(spans, span{start, end})
				// Set start to a negative value.
				// Note: using -1 here consistently and reproducibly
				// slows down this code by a several percent on amd64.
				start = ^start
			}

		} else {
			if start < 0 {
				start = end
			}
		}
	}

	// Last field might end at EOF.
	if start >= 0 {
		spans = append(spans, span{start, len(s)})
	}

	// Create strings from recorded field indices.
	a := make([]string, len(spans))
	for i, span := range spans {
		a[i] = s[span.start:span.end]
	}

	return a
}

/*CompareWithNumber 带数字的字符串比较
 *"abc100" < "abc9" true
 */
func CompareWithNumber(s1 string, s2 string) bool {
	var regStringNumber = regexp.MustCompile(`([A-Za-z]*)([\d]*)`)
	ss1 := regStringNumber.FindStringSubmatch(s1)
	ss2 := regStringNumber.FindStringSubmatch(s2)
	if len(ss1) == len(ss2) && len(ss1) == 3 {
		if ss1[1] < ss2[1] {
			return true
		} else if ss1[1] > ss2[1] {
			return false
		} else {
			i1, e1 := strconv.Atoi(ss1[2])
			i2, e2 := strconv.Atoi(ss2[2])
			if e1 != nil && e2 != nil {
				return ss1[2] < ss2[2]
			}
			return i1 < i2
		}
	}
	return s1 < s2
}
